home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / ShadowVolume / ShadowVolume.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  85.4 KB  |  1,833 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: ShadowVolume.cpp
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "resource.h"
  10.  
  11. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  12. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  13.  
  14.  
  15. #define DEFMESHFILENAME L"dwarf\\dwarf.x"
  16. #define MAX_NUM_LIGHTS 6
  17. #define ADJACENCY_EPSILON 0.0001f
  18. #define EXTRUDE_EPSILON 0.1f
  19. #define AMBIENT 0.10f
  20.  
  21. enum RENDER_TYPE { RENDERTYPE_SCENE, RENDERTYPE_SHADOWVOLUME, RENDERTYPE_COMPLEXITY };
  22.  
  23. D3DXVECTOR4 g_vShadowColor[MAX_NUM_LIGHTS] =
  24. {
  25.     D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 0.2f ),
  26.     D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 0.2f ),
  27.     D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 0.2f ),
  28.     D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 0.2f ),
  29.     D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 0.2f ),
  30.     D3DXVECTOR4( 0.0f, 1.0f, 1.0f, 0.2f )
  31. };
  32.  
  33.  
  34. struct LIGHTINITDATA
  35. {
  36.     D3DXVECTOR3 Position;
  37.     D3DXVECTOR4 Color;
  38. public:
  39.     LIGHTINITDATA() { }
  40.     LIGHTINITDATA( D3DXVECTOR3 P, D3DXVECTOR4 C )
  41.     {
  42.         Position = P;
  43.         Color = C;
  44.     }
  45. };
  46. LIGHTINITDATA g_LightInit[MAX_NUM_LIGHTS] =
  47. {
  48.     LIGHTINITDATA( D3DXVECTOR3( -2.0f, 3.0f, -3.0f ), D3DXVECTOR4( 15.0f, 15.0f, 15.0f, 1.0f ) ),
  49. #if MAX_NUM_LIGHTS > 1
  50.     LIGHTINITDATA(  D3DXVECTOR3( 2.0f, 3.0f, -3.0f ), D3DXVECTOR4( 15.0f, 15.0f, 15.0f, 1.0f ) ),
  51. #endif
  52. #if MAX_NUM_LIGHTS > 2
  53.     LIGHTINITDATA(  D3DXVECTOR3( -2.0f, 3.0f, 3.0f ), D3DXVECTOR4( 15.0f, 15.0f, 15.0f, 1.0f ) ),
  54. #endif
  55. #if MAX_NUM_LIGHTS > 3
  56.     LIGHTINITDATA(  D3DXVECTOR3( 2.0f, 3.0f, 3.0f ), D3DXVECTOR4( 15.0f, 15.0f, 15.0f, 1.0f ) ),
  57. #endif
  58. #if MAX_NUM_LIGHTS > 4
  59.     LIGHTINITDATA(  D3DXVECTOR3( -2.0f, 3.0f, 0.0f ), D3DXVECTOR4( 15.0f, 0.0f, 0.0f, 1.0f ) ),
  60. #endif
  61. #if MAX_NUM_LIGHTS > 5
  62.     LIGHTINITDATA(  D3DXVECTOR3( 2.0f, 3.0f, 0.0f ), D3DXVECTOR4( 0.0f, 0.0f, 15.0f, 1.0f ) )
  63. #endif
  64. };
  65.  
  66. struct POSTPROCVERT
  67. {
  68.     float x, y, z;
  69.     float rhw;
  70.  
  71.     const static D3DVERTEXELEMENT9 Decl[2];
  72. };
  73.  
  74. const D3DVERTEXELEMENT9 POSTPROCVERT::Decl[2] =
  75. {
  76.     { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 },
  77.     D3DDECL_END()
  78. };
  79.  
  80.  
  81. struct SHADOWVERT
  82. {
  83.     D3DXVECTOR3 Position;
  84.     D3DXVECTOR3 Normal;
  85.  
  86.     const static D3DVERTEXELEMENT9 Decl[3];
  87. };
  88.  
  89. const D3DVERTEXELEMENT9 SHADOWVERT::Decl[3] =
  90. {
  91.     { 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  92.     { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },
  93.     D3DDECL_END()
  94. };
  95.  
  96.  
  97. struct MESHVERT
  98. {
  99.     D3DXVECTOR3 Position;
  100.     D3DXVECTOR3 Normal;
  101.     D3DXVECTOR2 Tex;
  102.  
  103.     const static D3DVERTEXELEMENT9 Decl[4];
  104. };
  105.  
  106. const D3DVERTEXELEMENT9 MESHVERT::Decl[4] =
  107. {
  108.     { 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  109.     { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },
  110.     { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  111.     D3DDECL_END()
  112. };
  113.  
  114.  
  115. struct CEdgeMapping
  116. {
  117.     int m_anOldEdge[2];  // vertex index of the original edge
  118.     int m_aanNewEdge[2][2]; // vertex indexes of the new edge
  119.                             // First subscript = index of the new edge
  120.                             // Second subscript = index of the vertex for the edge
  121.  
  122. public:
  123.     CEdgeMapping()
  124.     {
  125.         FillMemory( m_anOldEdge, sizeof(m_anOldEdge), -1 );
  126.         FillMemory( m_aanNewEdge, sizeof(m_aanNewEdge), -1 );
  127.     }
  128. };
  129.  
  130.  
  131. struct CLight
  132. {
  133.     D3DXVECTOR3 m_Position;  // Light position
  134.     D3DXVECTOR4 m_Color;     // Light color
  135.     D3DXMATRIXA16 m_mWorld;  // World transform
  136. };
  137.  
  138.  
  139. //--------------------------------------------------------------------------------------
  140. // Global variables
  141. //--------------------------------------------------------------------------------------
  142. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  143. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  144. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  145. IDirect3DTexture9*      g_pDefaultTex = NULL;   // Default texture for faces without one
  146. IDirect3DVertexDeclaration9* g_pMeshDecl = NULL; // Vertex declaration for the meshes
  147. IDirect3DVertexDeclaration9* g_pShadowDecl = NULL;// Vertex declaration for the shadow volume
  148. IDirect3DVertexDeclaration9* g_pPProcDecl = NULL;// Vertex declaration for post-process quad rendering
  149. CFirstPersonCamera      g_Camera;               // Viewer's camera
  150. CModelViewerCamera      g_MCamera;              // Camera for mesh control
  151. CModelViewerCamera      g_LCamera;              // Camera for easy light movement control
  152. D3DXHANDLE              g_hRenderShadow;        // Technique handle for rendering shadow
  153. D3DXHANDLE              g_hShowShadow;          // Technique handle for showing shadow volume
  154. D3DXHANDLE              g_hRenderScene;         // Technique handle for rendering scene
  155. D3DXMATRIXA16           g_mWorldScaling;        // Scaling to apply to mesh
  156. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  157. bool                    g_bShowShadowVolume = false;  // Whether the shadow volume is visibly shown.
  158. RENDER_TYPE             g_RenderType = RENDERTYPE_SCENE;  // Type of rendering to perform
  159. int                     g_nNumLights = 1;       // Number of active lights
  160. CDXUTMesh               g_Background[2];        // Background meshes
  161. D3DXMATRIXA16           g_mWorldBack[2];        // Additional scaling and translation for background meshes
  162. int                     g_nCurrBackground = 0;  // Current background mesh
  163. CDXUTMesh               g_LightMesh;            // Mesh to represent the light source
  164. CDXUTMesh               g_Mesh;                 // The mesh object
  165. ID3DXMesh*              g_pShadowMesh = NULL;   // The shadow volume mesh
  166. CDXUTDialog             g_HUD;                  // dialog for standard controls
  167. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  168. D3DXMATRIXA16           g_mProjection;
  169. CLight                  g_aLights[MAX_NUM_LIGHTS];  // Light objects
  170. bool                    g_bLeftButtonDown = false;
  171. bool                    g_bRightButtonDown = false;
  172. bool                    g_bMiddleButtonDown = false;
  173.  
  174. //--------------------------------------------------------------------------------------
  175. // UI control IDs
  176. //--------------------------------------------------------------------------------------
  177. #define IDC_TOGGLEFULLSCREEN    1
  178. #define IDC_TOGGLEREF           3
  179. #define IDC_CHANGEDEVICE        4
  180. #define IDC_RENDERTYPE          5
  181. #define IDC_ENABLELIGHT         6
  182. #define IDC_LUMINANCELABEL      7
  183. #define IDC_LUMINANCE           8
  184. #define IDC_BACKGROUND          9
  185. #define IDC_CHANGEMESH          10
  186. #define IDC_MESHFILENAME        11
  187.  
  188.  
  189. //--------------------------------------------------------------------------------------
  190. // Forward declarations 
  191. //--------------------------------------------------------------------------------------
  192. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  193. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  194. void    CALLBACK ModifySettingsDlg( CDXUTDialog* pSettingsDialog );
  195. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  196. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  197. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  198. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  199. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  200. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  201. void    CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos );
  202. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  203. void    CALLBACK OnLostDevice();
  204. void    CALLBACK OnDestroyDevice();
  205.  
  206. void    InitApp();
  207. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh );
  208. void    RenderText();
  209.  
  210.  
  211.  
  212. //--------------------------------------------------------------------------------------
  213. // Takes an array of CEdgeMapping objects, then returns an index for the edge in the
  214. // table if such entry exists, or returns an index at which a new entry for the edge
  215. // can be written.
  216. // nV1 and nV2 are the vertex indexes for the old edge.
  217. // nCount is the number of elements in the array.
  218. // The function returns -1 if an available entry cannot be found.  In reality,
  219. // this should never happens as we should have allocated enough memory.
  220. int FindEdgeInMappingTable( int nV1, int nV2, CEdgeMapping *pMapping, int nCount )
  221. {
  222.     for( int i = 0; i < nCount; ++i )
  223.     {
  224.         // If both vertex indexes of the old edge in mapping entry are -1, then
  225.         // we have searched every valid entry without finding a match.  Return
  226.         // this index as a newly created entry.
  227.         if( ( pMapping[i].m_anOldEdge[0] == -1 && pMapping[i].m_anOldEdge[1] == -1 ) ||
  228.  
  229.             // Or if we find a match, return the index.
  230.             ( pMapping[i].m_anOldEdge[1] == nV1 && pMapping[i].m_anOldEdge[0] == nV2 ) )
  231.         {
  232.             return i;
  233.         }
  234.     }
  235.  
  236.     return -1;  // We should never reach this line
  237. }
  238.  
  239.  
  240. //--------------------------------------------------------------------------------------
  241. // Takes a mesh and generate a new mesh from it that contains the degenerate invisible
  242. // quads for shadow volume extrusion.
  243. HRESULT GenerateShadowMesh( IDirect3DDevice9 *pd3dDevice, ID3DXMesh *pMesh, ID3DXMesh **ppOutMesh )
  244. {
  245.     HRESULT hr = S_OK;
  246.     ID3DXMesh *pInputMesh;
  247.  
  248.     if( !ppOutMesh )
  249.         return E_INVALIDARG;
  250.     *ppOutMesh = NULL;
  251.  
  252.     // Convert the input mesh to a format same as the output mesh using 32-bit index.
  253.     hr = pMesh->CloneMesh( D3DXMESH_32BIT, SHADOWVERT::Decl, pd3dDevice, &pInputMesh );
  254.     if( FAILED( hr ) )
  255.         return hr;
  256.  
  257.     DXUTTRACE( L"Input mesh has %u vertices, %u faces\n", pInputMesh->GetNumVertices(), pInputMesh->GetNumFaces() );
  258.  
  259.     // Generate adjacency information
  260.     DWORD *pdwAdj = new DWORD[3 * pInputMesh->GetNumFaces()];
  261.     DWORD *pdwPtRep = new DWORD[pInputMesh->GetNumVertices()];
  262.     if( !pdwAdj || !pdwPtRep )
  263.     {
  264.         delete[] pdwAdj; delete[] pdwPtRep;
  265.         pInputMesh->Release();
  266.         return E_OUTOFMEMORY;
  267.     }
  268.  
  269.     hr = pInputMesh->GenerateAdjacency( ADJACENCY_EPSILON, pdwAdj );
  270.     if( FAILED( hr ) )
  271.     {
  272.         delete[] pdwAdj; delete[] pdwPtRep;
  273.         pInputMesh->Release();
  274.         return hr;
  275.     }
  276.  
  277.     pInputMesh->ConvertAdjacencyToPointReps( pdwAdj, pdwPtRep );
  278.     delete[] pdwAdj;
  279.  
  280.     SHADOWVERT *pVBData = NULL;
  281.     DWORD *pdwIBData = NULL;
  282.  
  283.     pInputMesh->LockVertexBuffer( 0, (LPVOID*)&pVBData );
  284.     pInputMesh->LockIndexBuffer( 0, (LPVOID*)&pdwIBData );
  285.  
  286.     if( pVBData && pdwIBData )
  287.     {
  288.         // Maximum number of unique edges = Number of faces * 3
  289.         DWORD dwNumEdges = pInputMesh->GetNumFaces() * 3;
  290.         CEdgeMapping *pMapping = new CEdgeMapping[dwNumEdges];
  291.         if( pMapping )
  292.         {
  293.             int nNumMaps = 0;  // Number of entries that exist in pMapping
  294.  
  295.             // Create a new mesh
  296.             ID3DXMesh *pNewMesh;
  297.             hr = D3DXCreateMesh( pInputMesh->GetNumFaces() + dwNumEdges * 2,
  298.                                  pInputMesh->GetNumFaces() * 3,
  299.                                  D3DXMESH_32BIT,
  300.                                  SHADOWVERT::Decl,
  301.                                  pd3dDevice,
  302.                                  &pNewMesh );
  303.             if( SUCCEEDED( hr ) )
  304.             {
  305.                 SHADOWVERT *pNewVBData = NULL;
  306.                 DWORD *pdwNewIBData = NULL;
  307.  
  308.                 pNewMesh->LockVertexBuffer( 0, (LPVOID*)&pNewVBData );
  309.                 pNewMesh->LockIndexBuffer( 0, (LPVOID*)&pdwNewIBData );
  310.  
  311.                 // nNextIndex is the array index in IB that the next vertex index value
  312.                 // will be store at.
  313.                 int nNextIndex = 0;
  314.  
  315.                 if( pNewVBData && pdwNewIBData )
  316.                 {
  317.                     ZeroMemory( pNewVBData, pNewMesh->GetNumVertices() * pNewMesh->GetNumBytesPerVertex() );
  318.                     ZeroMemory( pdwNewIBData, sizeof(DWORD) * pNewMesh->GetNumFaces() * 3 );
  319.  
  320.                     // pNextOutVertex is the location to write the next
  321.                     // vertex to.
  322.                     SHADOWVERT *pNextOutVertex = pNewVBData;
  323.  
  324.                     // Iterate through the faces.  For each face, output new
  325.                     // vertices and face in the new mesh, and write its edges
  326.                     // to the mapping table.
  327.  
  328.                     for( UINT f = 0; f < pInputMesh->GetNumFaces(); ++f )
  329.                     {
  330.                         // Copy the vertex data for all 3 vertices
  331.                         CopyMemory( pNextOutVertex, pVBData + pdwIBData[f * 3], sizeof(SHADOWVERT) );
  332.                         CopyMemory( pNextOutVertex + 1, pVBData + pdwIBData[f * 3 + 1], sizeof(SHADOWVERT) );
  333.                         CopyMemory( pNextOutVertex + 2, pVBData + pdwIBData[f * 3 + 2], sizeof(SHADOWVERT) );
  334.  
  335.                         // Write out the face
  336.                         pdwNewIBData[nNextIndex++] = f * 3;
  337.                         pdwNewIBData[nNextIndex++] = f * 3 + 1;
  338.                         pdwNewIBData[nNextIndex++] = f * 3 + 2;
  339.  
  340.                         // Compute the face normal and assign it to
  341.                         // the normals of the vertices.
  342.                         D3DXVECTOR3 v1, v2;  // v1 and v2 are the edge vectors of the face
  343.                         D3DXVECTOR3 vNormal;
  344.                         v1 = *(D3DXVECTOR3*)(pNextOutVertex + 1) - *(D3DXVECTOR3*)pNextOutVertex;
  345.                         v2 = *(D3DXVECTOR3*)(pNextOutVertex + 2) - *(D3DXVECTOR3*)(pNextOutVertex + 1);
  346.                         D3DXVec3Cross( &vNormal, &v1, &v2 );
  347.                         D3DXVec3Normalize( &vNormal, &vNormal );
  348.  
  349.                         pNextOutVertex->Normal = vNormal;
  350.                         (pNextOutVertex + 1)->Normal = vNormal;
  351.                         (pNextOutVertex + 2)->Normal = vNormal;
  352.  
  353.                         pNextOutVertex += 3;
  354.  
  355.                         // Add the face's edges to the edge mapping table
  356.  
  357.                         // Edge 1
  358.                         int nIndex;
  359.                         int nVertIndex[3] = { pdwPtRep[pdwIBData[f * 3]],
  360.                                               pdwPtRep[pdwIBData[f * 3 + 1]],
  361.                                               pdwPtRep[pdwIBData[f * 3 + 2]] };
  362.                         nIndex = FindEdgeInMappingTable( nVertIndex[0], nVertIndex[1], pMapping, dwNumEdges );
  363.  
  364.                         // If error, we are not able to proceed, so abort.
  365.                         if( -1 == nIndex )
  366.                         {
  367.                             hr = E_INVALIDARG;
  368.                             goto cleanup;
  369.                         }
  370.  
  371.                         if( pMapping[nIndex].m_anOldEdge[0] == -1 && pMapping[nIndex].m_anOldEdge[1] == -1 )
  372.                         {
  373.                             // No entry for this edge yet.  Initialize one.
  374.                             pMapping[nIndex].m_anOldEdge[0] = nVertIndex[0];
  375.                             pMapping[nIndex].m_anOldEdge[1] = nVertIndex[1];
  376.                             pMapping[nIndex].m_aanNewEdge[0][0] = f * 3;
  377.                             pMapping[nIndex].m_aanNewEdge[0][1] = f * 3 + 1;
  378.  
  379.                             ++nNumMaps;
  380.                         } else
  381.                         {
  382.                             // An entry is found for this edge.  Create
  383.                             // a quad and output it.
  384.                             assert( nNumMaps > 0 );
  385.  
  386.                             pMapping[nIndex].m_aanNewEdge[1][0] = f * 3;      // For clarity
  387.                             pMapping[nIndex].m_aanNewEdge[1][1] = f * 3 + 1;
  388.  
  389.                             // First triangle
  390.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][1];
  391.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  392.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  393.  
  394.                             // Second triangle
  395.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][1];
  396.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  397.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  398.  
  399.                             // pMapping[nIndex] is no longer needed. Copy the last map entry
  400.                             // over and decrement the map count.
  401.  
  402.                             pMapping[nIndex] = pMapping[nNumMaps-1];
  403.                             FillMemory( &pMapping[nNumMaps-1], sizeof( pMapping[nNumMaps-1] ), 0xFF );
  404.                             --nNumMaps;
  405.                         }
  406.  
  407.                         // Edge 2
  408.                         nIndex = FindEdgeInMappingTable( nVertIndex[1], nVertIndex[2], pMapping, dwNumEdges );
  409.  
  410.                         // If error, we are not able to proceed, so abort.
  411.                         if( -1 == nIndex )
  412.                         {
  413.                             hr = E_INVALIDARG;
  414.                             goto cleanup;
  415.                         }
  416.  
  417.                         if( pMapping[nIndex].m_anOldEdge[0] == -1 && pMapping[nIndex].m_anOldEdge[1] == -1 )
  418.                         {
  419.                             pMapping[nIndex].m_anOldEdge[0] = nVertIndex[1];
  420.                             pMapping[nIndex].m_anOldEdge[1] = nVertIndex[2];
  421.                             pMapping[nIndex].m_aanNewEdge[0][0] = f * 3 + 1;
  422.                             pMapping[nIndex].m_aanNewEdge[0][1] = f * 3 + 2;
  423.  
  424.                             ++nNumMaps;
  425.                         } else
  426.                         {
  427.                             // An entry is found for this edge.  Create
  428.                             // a quad and output it.
  429.                             assert( nNumMaps > 0 );
  430.  
  431.                             pMapping[nIndex].m_aanNewEdge[1][0] = f * 3 + 1;
  432.                             pMapping[nIndex].m_aanNewEdge[1][1] = f * 3 + 2;
  433.  
  434.                             // First triangle
  435.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][1];
  436.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  437.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  438.  
  439.                             // Second triangle
  440.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][1];
  441.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  442.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  443.  
  444.                             // pMapping[nIndex] is no longer needed. Copy the last map entry
  445.                             // over and decrement the map count.
  446.  
  447.                             pMapping[nIndex] = pMapping[nNumMaps-1];
  448.                             FillMemory( &pMapping[nNumMaps-1], sizeof( pMapping[nNumMaps-1] ), 0xFF );
  449.                             --nNumMaps;
  450.                         }
  451.  
  452.                         // Edge 3
  453.                         nIndex = FindEdgeInMappingTable( nVertIndex[2], nVertIndex[0], pMapping, dwNumEdges );
  454.  
  455.                         // If error, we are not able to proceed, so abort.
  456.                         if( -1 == nIndex )
  457.                         {
  458.                             hr = E_INVALIDARG;
  459.                             goto cleanup;
  460.                         }
  461.  
  462.                         if( pMapping[nIndex].m_anOldEdge[0] == -1 && pMapping[nIndex].m_anOldEdge[1] == -1 )
  463.                         {
  464.                             pMapping[nIndex].m_anOldEdge[0] = nVertIndex[2];
  465.                             pMapping[nIndex].m_anOldEdge[1] = nVertIndex[0];
  466.                             pMapping[nIndex].m_aanNewEdge[0][0] = f * 3 + 2;
  467.                             pMapping[nIndex].m_aanNewEdge[0][1] = f * 3;
  468.  
  469.                             ++nNumMaps;
  470.                         } else
  471.                         {
  472.                             // An entry is found for this edge.  Create
  473.                             // a quad and output it.
  474.                             assert( nNumMaps > 0 );
  475.  
  476.                             pMapping[nIndex].m_aanNewEdge[1][0] = f * 3 + 2;
  477.                             pMapping[nIndex].m_aanNewEdge[1][1] = f * 3;
  478.  
  479.                             // First triangle
  480.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][1];
  481.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  482.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  483.  
  484.                             // Second triangle
  485.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][1];
  486.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  487.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  488.  
  489.                             // pMapping[nIndex] is no longer needed. Copy the last map entry
  490.                             // over and decrement the map count.
  491.  
  492.                             pMapping[nIndex] = pMapping[nNumMaps-1];
  493.                             FillMemory( &pMapping[nNumMaps-1], sizeof( pMapping[nNumMaps-1] ), 0xFF );
  494.                             --nNumMaps;
  495.                         }
  496.                     }
  497.  
  498.                     // Now the entries in the edge mapping table represent
  499.                     // non-shared edges.  What they mean is that the original
  500.                     // mesh has openings (holes), so we attempt to patch them.
  501.                     // First we need to recreate our mesh with a larger vertex
  502.                     // and index buffers so the patching geometry could fit.
  503.  
  504.                     DXUTTRACE( L"Faces to patch: %d\n", nNumMaps );
  505.  
  506.                     // Create a mesh with large enough vertex and
  507.                     // index buffers.
  508.  
  509.                     SHADOWVERT *pPatchVBData = NULL;
  510.                     DWORD *pdwPatchIBData = NULL;
  511.  
  512.                     ID3DXMesh *pPatchMesh = NULL;
  513.                     // Make enough room in IB for the face and up to 3 quads for each patching face
  514.                     hr = D3DXCreateMesh( nNextIndex / 3 + nNumMaps * 7,
  515.                                          ( pInputMesh->GetNumFaces() + nNumMaps ) * 3,
  516.                                          D3DXMESH_32BIT,
  517.                                          SHADOWVERT::Decl,
  518.                                          pd3dDevice,
  519.                                          &pPatchMesh );
  520.  
  521.                     if( FAILED( hr ) )
  522.                         goto cleanup;
  523.  
  524.                     hr = pPatchMesh->LockVertexBuffer( 0, (LPVOID*)&pPatchVBData );
  525.                     if( SUCCEEDED( hr ) )
  526.                         hr = pPatchMesh->LockIndexBuffer( 0, (LPVOID*)&pdwPatchIBData );
  527.  
  528.                     if( pPatchVBData && pdwPatchIBData )
  529.                     {
  530.                         ZeroMemory( pPatchVBData, sizeof(SHADOWVERT) * ( pInputMesh->GetNumFaces() + nNumMaps ) * 3 );
  531.                         ZeroMemory( pdwPatchIBData, sizeof(DWORD) * ( nNextIndex + 3 * nNumMaps * 7 ) );
  532.  
  533.                         // Copy the data from one mesh to the other
  534.  
  535.                         CopyMemory( pPatchVBData, pNewVBData, sizeof(SHADOWVERT) * pInputMesh->GetNumFaces() * 3 );
  536.                         CopyMemory( pdwPatchIBData, pdwNewIBData, sizeof(DWORD) * nNextIndex );
  537.                     } else
  538.                     {
  539.                         // Some serious error is preventing us from locking.
  540.                         // Abort and return error.
  541.  
  542.                         pPatchMesh->Release();
  543.                         goto cleanup;
  544.                     }
  545.  
  546.                     // Replace pNewMesh with the updated one.  Then the code
  547.                     // can continue working with the pNewMesh pointer.
  548.  
  549.                     pNewMesh->UnlockVertexBuffer();
  550.                     pNewMesh->UnlockIndexBuffer();
  551.                     pNewVBData = pPatchVBData;
  552.                     pdwNewIBData = pdwPatchIBData;
  553.                     pNewMesh->Release();
  554.                     pNewMesh = pPatchMesh;
  555.  
  556.                     // Now, we iterate through the edge mapping table and
  557.                     // for each shared edge, we generate a quad.
  558.                     // For each non-shared edge, we patch the opening
  559.                     // with new faces.
  560.  
  561.                     // nNextVertex is the index of the next vertex.
  562.                     int nNextVertex = pInputMesh->GetNumFaces() * 3;
  563.  
  564.                     for( int i = 0; i < nNumMaps; ++i )
  565.                     {
  566.                         if( pMapping[i].m_anOldEdge[0] != -1 &&
  567.                             pMapping[i].m_anOldEdge[1] != -1 )
  568.                         {
  569.                             // If the 2nd new edge indexes is -1,
  570.                             // this edge is a non-shared one.
  571.                             // We patch the opening by creating new
  572.                             // faces.
  573.                             if( pMapping[i].m_aanNewEdge[1][0] == -1 ||  // must have only one new edge
  574.                                 pMapping[i].m_aanNewEdge[1][1] == -1 )
  575.                             {
  576.                                 // Find another non-shared edge that
  577.                                 // shares a vertex with the current edge.
  578.                                 for( int i2 = i + 1; i2 < nNumMaps; ++i2 )
  579.                                 {
  580.                                     if( pMapping[i2].m_anOldEdge[0] != -1 &&       // must have a valid old edge
  581.                                         pMapping[i2].m_anOldEdge[1] != -1 &&
  582.                                         ( pMapping[i2].m_aanNewEdge[1][0] == -1 || // must have only one new edge
  583.                                         pMapping[i2].m_aanNewEdge[1][1] == -1 ) )
  584.                                     {
  585.                                         int nVertShared = 0;
  586.                                         if( pMapping[i2].m_anOldEdge[0] == pMapping[i].m_anOldEdge[1] )
  587.                                             ++nVertShared;
  588.                                         if( pMapping[i2].m_anOldEdge[1] == pMapping[i].m_anOldEdge[0] )
  589.                                             ++nVertShared;
  590.  
  591.                                         if( 2 == nVertShared )
  592.                                         {
  593.                                             // These are the last two edges of this particular
  594.                                             // opening. Mark this edge as shared so that a degenerate
  595.                                             // quad can be created for it.
  596.  
  597.                                             pMapping[i2].m_aanNewEdge[1][0] = pMapping[i].m_aanNewEdge[0][0];
  598.                                             pMapping[i2].m_aanNewEdge[1][1] = pMapping[i].m_aanNewEdge[0][1];
  599.                                             break;
  600.                                         }
  601.                                         else
  602.                                         if( 1 == nVertShared )
  603.                                         {
  604.                                             // nBefore and nAfter tell us which edge comes before the other.
  605.                                             int nBefore, nAfter;
  606.                                             if( pMapping[i2].m_anOldEdge[0] == pMapping[i].m_anOldEdge[1] )
  607.                                             {
  608.                                                 nBefore = i;
  609.                                                 nAfter = i2;
  610.                                             } else
  611.                                             {
  612.                                                 nBefore = i2;
  613.                                                 nAfter = i;
  614.                                             }
  615.  
  616.                                             // Found such an edge. Now create a face along with two
  617.                                             // degenerate quads from these two edges.
  618.  
  619.                                             pNewVBData[nNextVertex] = pNewVBData[pMapping[nAfter].m_aanNewEdge[0][1]];
  620.                                             pNewVBData[nNextVertex+1] = pNewVBData[pMapping[nBefore].m_aanNewEdge[0][1]];
  621.                                             pNewVBData[nNextVertex+2] = pNewVBData[pMapping[nBefore].m_aanNewEdge[0][0]];
  622.                                             // Recompute the normal
  623.                                             D3DXVECTOR3 v1 = pNewVBData[nNextVertex+1].Position - pNewVBData[nNextVertex].Position;
  624.                                             D3DXVECTOR3 v2 = pNewVBData[nNextVertex+2].Position - pNewVBData[nNextVertex+1].Position;
  625.                                             D3DXVec3Normalize( &v1, &v1 );
  626.                                             D3DXVec3Normalize( &v2, &v2 );
  627.                                             D3DXVec3Cross( &pNewVBData[nNextVertex].Normal, &v1, &v2 );
  628.                                             pNewVBData[nNextVertex+1].Normal = pNewVBData[nNextVertex+2].Normal = pNewVBData[nNextVertex].Normal;
  629.  
  630.                                             pdwNewIBData[nNextIndex] = nNextVertex;
  631.                                             pdwNewIBData[nNextIndex+1] = nNextVertex + 1;
  632.                                             pdwNewIBData[nNextIndex+2] = nNextVertex + 2;
  633.  
  634.                                             // 1st quad
  635.  
  636.                                             pdwNewIBData[nNextIndex+3] = pMapping[nBefore].m_aanNewEdge[0][1];
  637.                                             pdwNewIBData[nNextIndex+4] = pMapping[nBefore].m_aanNewEdge[0][0];
  638.                                             pdwNewIBData[nNextIndex+5] = nNextVertex + 1;
  639.  
  640.                                             pdwNewIBData[nNextIndex+6] = nNextVertex + 2;
  641.                                             pdwNewIBData[nNextIndex+7] = nNextVertex + 1;
  642.                                             pdwNewIBData[nNextIndex+8] = pMapping[nBefore].m_aanNewEdge[0][0];
  643.  
  644.                                             // 2nd quad
  645.  
  646.                                             pdwNewIBData[nNextIndex+9] = pMapping[nAfter].m_aanNewEdge[0][1];
  647.                                             pdwNewIBData[nNextIndex+10] = pMapping[nAfter].m_aanNewEdge[0][0];
  648.                                             pdwNewIBData[nNextIndex+11] = nNextVertex;
  649.  
  650.                                             pdwNewIBData[nNextIndex+12] = nNextVertex + 1;
  651.                                             pdwNewIBData[nNextIndex+13] = nNextVertex;
  652.                                             pdwNewIBData[nNextIndex+14] = pMapping[nAfter].m_aanNewEdge[0][0];
  653.  
  654.                                             // Modify mapping entry i2 to reflect the third edge
  655.                                             // of the newly added face.
  656.  
  657.                                             if( pMapping[i2].m_anOldEdge[0] == pMapping[i].m_anOldEdge[1] )
  658.                                             {
  659.                                                 pMapping[i2].m_anOldEdge[0] = pMapping[i].m_anOldEdge[0];
  660.                                             } else
  661.                                             {
  662.                                                 pMapping[i2].m_anOldEdge[1] = pMapping[i].m_anOldEdge[1];
  663.                                             }
  664.                                             pMapping[i2].m_aanNewEdge[0][0] = nNextVertex + 2;
  665.                                             pMapping[i2].m_aanNewEdge[0][1] = nNextVertex;
  666.  
  667.                                             // Update next vertex/index positions
  668.  
  669.                                             nNextVertex += 3;
  670.                                             nNextIndex += 15;
  671.  
  672.                                             break;
  673.                                         }
  674.                                     }
  675.                                 }
  676.                             } else
  677.                             {
  678.                                 // This is a shared edge.  Create the degenerate quad.
  679.  
  680.                                 // First triangle
  681.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[0][1];
  682.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[0][0];
  683.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[1][0];
  684.  
  685.                                 // Second triangle
  686.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[1][1];
  687.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[1][0];
  688.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[0][0];
  689.                             }
  690.                         }
  691.                     }
  692.                 }
  693.  
  694. cleanup:;
  695.                 if( pNewVBData )
  696.                 {
  697.                     pNewMesh->UnlockVertexBuffer();
  698.                     pNewVBData = NULL;
  699.                 }
  700.                 if( pdwNewIBData )
  701.                 {
  702.                     pNewMesh->UnlockIndexBuffer();
  703.                     pdwNewIBData = NULL;
  704.                 }
  705.  
  706.                 if( SUCCEEDED( hr ) )
  707.                 {
  708.                     // At this time, the output mesh may have an index buffer
  709.                     // bigger than what is actually needed, so we create yet
  710.                     // another mesh with the exact IB size that we need and
  711.                     // output it.  This mesh also uses 16-bit index if
  712.                     // 32-bit is not necessary.
  713.  
  714.                     DXUTTRACE( L"Shadow volume has %u vertices, %u faces.\n", ( pInputMesh->GetNumFaces() + nNumMaps ) * 3, nNextIndex / 3 );
  715.  
  716.                     bool bNeed32Bit = ( pInputMesh->GetNumFaces() + nNumMaps ) * 3 > 65535;
  717.                     ID3DXMesh *pFinalMesh;
  718.                     hr = D3DXCreateMesh( nNextIndex / 3,  // Exact number of faces
  719.                                          ( pInputMesh->GetNumFaces() + nNumMaps ) * 3,
  720.                                          D3DXMESH_WRITEONLY | ( bNeed32Bit ? D3DXMESH_32BIT : 0 ),
  721.                                          SHADOWVERT::Decl,
  722.                                          pd3dDevice,
  723.                                          &pFinalMesh );
  724.                     if( SUCCEEDED( hr ) )
  725.                     {
  726.                         pNewMesh->LockVertexBuffer( 0, (LPVOID*)&pNewVBData );
  727.                         pNewMesh->LockIndexBuffer( 0, (LPVOID*)&pdwNewIBData );
  728.  
  729.                         SHADOWVERT *pFinalVBData = NULL;
  730.                         WORD *pwFinalIBData = NULL;
  731.  
  732.                         pFinalMesh->LockVertexBuffer( 0, (LPVOID*)&pFinalVBData );
  733.                         pFinalMesh->LockIndexBuffer( 0, (LPVOID*)&pwFinalIBData );
  734.  
  735.                         if( pNewVBData && pdwNewIBData && pFinalVBData && pwFinalIBData )
  736.                         {
  737.                             CopyMemory( pFinalVBData, pNewVBData, sizeof(SHADOWVERT) * ( pInputMesh->GetNumFaces() + nNumMaps ) * 3 );
  738.  
  739.                             if( bNeed32Bit )
  740.                                 CopyMemory( pwFinalIBData, pdwNewIBData, sizeof(DWORD) * nNextIndex );
  741.                             else
  742.                             {
  743.                                 for( int i = 0; i < nNextIndex; ++i )
  744.                                     pwFinalIBData[i] = (WORD)pdwNewIBData[i];
  745.                             }
  746.                         }
  747.  
  748.                         if( pNewVBData )
  749.                             pNewMesh->UnlockVertexBuffer();
  750.                         if( pdwNewIBData )
  751.                             pNewMesh->UnlockIndexBuffer();
  752.                         if( pFinalVBData )
  753.                             pFinalMesh->UnlockVertexBuffer();
  754.                         if( pwFinalIBData )
  755.                             pFinalMesh->UnlockIndexBuffer();
  756.  
  757.                         // Release the old
  758.                         pNewMesh->Release();
  759.                         pNewMesh = pFinalMesh;
  760.                     }
  761.  
  762.                     *ppOutMesh = pNewMesh;
  763.                 }
  764.                 else
  765.                     pNewMesh->Release();
  766.             }
  767.             delete[] pMapping;
  768.         } else
  769.             hr = E_OUTOFMEMORY;
  770.     } else
  771.         hr = E_FAIL;
  772.  
  773.     if( pVBData )
  774.         pInputMesh->UnlockVertexBuffer();
  775.  
  776.     if( pdwIBData )
  777.         pInputMesh->UnlockIndexBuffer();
  778.  
  779.     delete[] pdwPtRep;
  780.     pInputMesh->Release();
  781.  
  782.     return hr;
  783. }
  784.  
  785.  
  786. //--------------------------------------------------------------------------------------
  787. // Entry point to the program. Initializes everything and goes into a message processing 
  788. // loop. Idle time is used to render the scene.
  789. //--------------------------------------------------------------------------------------
  790. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  791. {
  792.     // Set the callback functions. These functions allow the sample framework to notify
  793.     // the application about device changes, user input, and windows messages.  The 
  794.     // callbacks are optional so you need only set callbacks for events you're interested 
  795.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  796.     // framework won't be able to reset your device since the application must first 
  797.     // release all device resources before resetting.  Likewise, if you don't handle the 
  798.     // device created/destroyed callbacks then the sample framework won't be able to 
  799.     // recreate your device resources.
  800.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  801.     DXUTSetCallbackDeviceReset( OnResetDevice );
  802.     DXUTSetCallbackDeviceLost( OnLostDevice );
  803.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  804.     DXUTSetCallbackMsgProc( MsgProc );
  805.     DXUTSetCallbackKeyboard( KeyboardProc );
  806.     DXUTSetCallbackMouse( MouseProc );
  807.     DXUTSetCallbackFrameRender( OnFrameRender );
  808.     DXUTSetCallbackFrameMove( OnFrameMove );
  809.  
  810.     // This sample requires a stencil buffer. See the callback function for details.
  811.     CGrowableArray<D3DFORMAT>* pDSFormats = DXUTGetEnumeration()->GetPossibleDepthStencilFormatList();
  812.     pDSFormats->RemoveAll();
  813.     pDSFormats->Add( D3DFMT_D24S8 );
  814.     pDSFormats->Add( D3DFMT_D24X4S4 );
  815.     pDSFormats->Add( D3DFMT_D15S1 );
  816.     pDSFormats->Add( D3DFMT_D24FS8 );
  817.  
  818.     // Show the cursor and clip it when in full screen
  819.     DXUTSetCursorSettings( true, true );
  820.  
  821.     InitApp();
  822.  
  823.     // Initialize the scaling and translation for the background meshes
  824.     // Hardcode the matrices since we only have two.
  825.     D3DXMATRIXA16 m;
  826.     D3DXMatrixTranslation( &g_mWorldBack[0], 0.0f, 2.0f, 0.0f );
  827.     D3DXMatrixScaling( &g_mWorldBack[1], 0.3f, 0.3f, 0.3f );
  828.     D3DXMatrixTranslation( &m, 0.0f, 1.5f, 0.0f );
  829.     D3DXMatrixMultiply( &g_mWorldBack[1], &g_mWorldBack[1], &m );
  830.  
  831.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  832.     // device for the application. Calling each of these functions is optional, but they
  833.     // allow you to set several options which control the behavior of the framework.
  834.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  835.     DXUTCreateWindow( L"ShadowVolume" );
  836.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  837.  
  838.     // Pass control to the sample framework for handling the message pump and 
  839.     // dispatching render calls. The sample framework will call your FrameMove 
  840.     // and FrameRender callback when there is idle time between handling window messages.
  841.     DXUTMainLoop();
  842.  
  843.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  844.     // appropriate callback functions and therefore don't require any cleanup code here.
  845.  
  846.     return DXUTGetExitCode();
  847. }
  848.  
  849.  
  850. //--------------------------------------------------------------------------------------
  851. // Initialize the app 
  852. //--------------------------------------------------------------------------------------
  853. void InitApp()
  854. {
  855.     // Initialize dialogs
  856.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  857.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  858.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  859.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  860.  
  861.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10;
  862.     g_SampleUI.AddComboBox( IDC_BACKGROUND, 0, iY += 24, 190, 22, 0, false );
  863.     g_SampleUI.GetComboBox( IDC_BACKGROUND )->SetDropHeight( 40 );
  864.     g_SampleUI.GetComboBox( IDC_BACKGROUND )->AddItem( L"Background: Cell", (LPVOID)0 );
  865.     g_SampleUI.GetComboBox( IDC_BACKGROUND )->AddItem( L"Background: Field", (LPVOID)1 );
  866.     g_SampleUI.AddComboBox( IDC_ENABLELIGHT, 0, iY += 24, 190, 22, 0, false );
  867.     g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->SetDropHeight( 90 );
  868.     g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->AddItem( L"1 light", (LPVOID)1 );
  869.     g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->AddItem( L"2 lights", (LPVOID)2 );
  870.     g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->AddItem( L"3 lights", (LPVOID)3 );
  871.     g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->AddItem( L"4 lights", (LPVOID)4 );
  872.     g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->AddItem( L"5 lights", (LPVOID)5 );
  873.     g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->AddItem( L"6 lights", (LPVOID)6 );
  874.     g_SampleUI.AddComboBox( IDC_RENDERTYPE, 0, iY += 24, 190, 22, 0, false );
  875.     g_SampleUI.GetComboBox( IDC_RENDERTYPE )->SetDropHeight( 50 );
  876.     g_SampleUI.GetComboBox( IDC_RENDERTYPE )->AddItem( L"Scene with shadow", (LPVOID)RENDERTYPE_SCENE );
  877.     g_SampleUI.GetComboBox( IDC_RENDERTYPE )->AddItem( L"Show shadow volume", (LPVOID)RENDERTYPE_SHADOWVOLUME );
  878.     g_SampleUI.GetComboBox( IDC_RENDERTYPE )->AddItem( L"Shadow volume complexity", (LPVOID)RENDERTYPE_COMPLEXITY );
  879.     g_SampleUI.AddStatic( IDC_LUMINANCELABEL, L"Luminance: 15.0", 45, iY += 30, 125, 22 );
  880.     g_SampleUI.AddSlider( IDC_LUMINANCE, 45, iY += 20, 125, 22, 1, 40, 15 );
  881.     g_SampleUI.AddButton( IDC_CHANGEMESH, L"Change mesh", 80, iY += 26, 120, 40 );
  882.  
  883.     // Initialize cameras
  884.     g_Camera.SetRotateButtons( true, false, false );
  885.     g_MCamera.SetButtonMasks( MOUSE_RIGHT_BUTTON, 0, 0 );
  886.     g_LCamera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, 0, 0 );
  887.  
  888.     // Initialize the lights
  889.     for( int L = 0; L < MAX_NUM_LIGHTS; ++L )
  890.     {
  891.         D3DXMATRIXA16 m;
  892.         D3DXVECTOR4 v;
  893.         D3DXMatrixScaling( &g_aLights[L].m_mWorld, 0.1f, 0.1f, 0.1f );
  894.         D3DXMatrixTranslation( &m, g_LightInit[L].Position.x,
  895.                                    g_LightInit[L].Position.y,
  896.                                    g_LightInit[L].Position.z );
  897.         D3DXMatrixMultiply( &g_aLights[L].m_mWorld, &g_aLights[L].m_mWorld, &m );
  898.         g_aLights[L].m_Position = g_LightInit[L].Position;
  899.         g_aLights[L].m_Color = g_LightInit[L].Color;
  900.     }
  901. }
  902.  
  903.  
  904. //--------------------------------------------------------------------------------------
  905. // Returns true if a particular depth-stencil format can be created and used with
  906. // an adapter format and backbuffer format combination.
  907. BOOL IsDepthFormatOk( D3DFORMAT DepthFormat,
  908.                       D3DFORMAT AdapterFormat,
  909.                       D3DFORMAT BackBufferFormat )
  910. {
  911.     // Verify that the depth format exists
  912.     HRESULT hr = DXUTGetD3DObject()->CheckDeviceFormat( D3DADAPTER_DEFAULT,
  913.                                                         D3DDEVTYPE_HAL,
  914.                                                         AdapterFormat,
  915.                                                         D3DUSAGE_DEPTHSTENCIL,
  916.                                                         D3DRTYPE_SURFACE,
  917.                                                         DepthFormat );
  918.     if( FAILED( hr ) ) return FALSE;
  919.  
  920.     // Verify that the backbuffer format is valid
  921.     hr = DXUTGetD3DObject()->CheckDeviceFormat( D3DADAPTER_DEFAULT,
  922.                                                 D3DDEVTYPE_HAL,
  923.                                                 AdapterFormat,
  924.                                                 D3DUSAGE_RENDERTARGET,
  925.                                                 D3DRTYPE_SURFACE,
  926.                                                 BackBufferFormat );
  927.     if( FAILED( hr ) ) return FALSE;
  928.  
  929.     // Verify that the depth format is compatible
  930.     hr = DXUTGetD3DObject()->CheckDepthStencilMatch( D3DADAPTER_DEFAULT,
  931.                                                      D3DDEVTYPE_HAL,
  932.                                                      AdapterFormat,
  933.                                                      BackBufferFormat,
  934.                                                      DepthFormat );
  935.  
  936.     return SUCCEEDED(hr);
  937. }
  938.  
  939.  
  940. //--------------------------------------------------------------------------------------
  941. // Called during device initialization, this code checks the device for some 
  942. // minimum set of capabilities, and rejects those that don't pass by returning false.
  943. //--------------------------------------------------------------------------------------
  944. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  945.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  946. {
  947.     // Skip backbuffer formats that don't support alpha blending
  948.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  949.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  950.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  951.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  952.         return false;
  953.  
  954.     // Must support pixel shader 1.1
  955.     if( pCaps->PixelShaderVersion < D3DPS_VERSION( 1, 1 ) )
  956.         return false;
  957.  
  958.     // Must support stencil buffer
  959.     if( !IsDepthFormatOk( D3DFMT_D24S8,
  960.                           AdapterFormat,
  961.                           BackBufferFormat ) &&
  962.         !IsDepthFormatOk( D3DFMT_D24X4S4,
  963.                           AdapterFormat,
  964.                           BackBufferFormat ) &&
  965.         !IsDepthFormatOk( D3DFMT_D15S1,
  966.                           AdapterFormat,
  967.                           BackBufferFormat ) &&
  968.         !IsDepthFormatOk( D3DFMT_D24FS8,
  969.                           AdapterFormat,
  970.                           BackBufferFormat ) )
  971.         return false;
  972.  
  973.     return true;
  974. }
  975.  
  976.  
  977. //--------------------------------------------------------------------------------------
  978. // This callback function is called immediately before a device is created to allow the 
  979. // application to modify the device settings. The supplied pDeviceSettings parameter 
  980. // contains the settings that the framework has selected for the new device, and the 
  981. // application can make any desired changes directly to this structure.  Note however that 
  982. // the sample framework will not correct invalid device settings so care must be taken 
  983. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  984. //--------------------------------------------------------------------------------------
  985. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  986. {
  987.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  988.     // then switch to SWVP.
  989.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  990.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  991.     {
  992.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  993.     }
  994.     else
  995.     {
  996.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  997.     }
  998.  
  999.     // Debugging vertex shaders requires either REF or software vertex processing 
  1000.     // and debugging pixel shaders requires REF.  
  1001. #ifdef DEBUG_VS
  1002.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  1003.     {
  1004.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1005.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  1006.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1007.     }
  1008. #endif
  1009. #ifdef DEBUG_PS
  1010.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  1011. #endif
  1012.  
  1013.     // This sample requires a stencil buffer.
  1014.     if( IsDepthFormatOk( D3DFMT_D24S8,
  1015.                          pDeviceSettings->AdapterFormat,
  1016.                          pDeviceSettings->pp.BackBufferFormat ) )
  1017.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24S8;
  1018.     else
  1019.     if( IsDepthFormatOk( D3DFMT_D24X4S4,
  1020.                          pDeviceSettings->AdapterFormat,
  1021.                          pDeviceSettings->pp.BackBufferFormat ) )
  1022.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24X4S4;
  1023.     else
  1024.     if( IsDepthFormatOk( D3DFMT_D24FS8,
  1025.                          pDeviceSettings->AdapterFormat,
  1026.                          pDeviceSettings->pp.BackBufferFormat ) )
  1027.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24FS8;
  1028.     else
  1029.     if( IsDepthFormatOk( D3DFMT_D15S1,
  1030.                          pDeviceSettings->AdapterFormat,
  1031.                          pDeviceSettings->pp.BackBufferFormat ) )
  1032.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D15S1;
  1033. }
  1034.  
  1035.  
  1036. //--------------------------------------------------------------------------------------
  1037. // This function is called after the D3D Settings Dialog is refreshed, giving the
  1038. // application a chance to modify the dialog contents before being displayed to the
  1039. // user.
  1040. //--------------------------------------------------------------------------------------
  1041. void CALLBACK ModifySettingsDlg( CDXUTDialog* pSettingsDialog )
  1042. {
  1043.     CDXUTComboBox* pComboBox = NULL;
  1044.  
  1045.     pComboBox = pSettingsDialog->GetComboBox( DXUTSETTINGSDLG_DEPTH_STENCIL );
  1046.     for( int i = pComboBox->GetNumItems() - 1; i >= 0; --i )
  1047.     {
  1048.         DXUTComboBoxItem* pItem = pComboBox->GetItem( i );
  1049.         if( pItem->pData != (void*)D3DFMT_D24S8 &&
  1050.             pItem->pData != (void*)D3DFMT_D24X4S4 &&
  1051.             pItem->pData != (void*)D3DFMT_D15S1 &&
  1052.             pItem->pData != (void*)D3DFMT_D24FS8 )
  1053.             pComboBox->RemoveItem( i );
  1054.     }
  1055. }
  1056.  
  1057.  
  1058. // Compute a matrix that scales Mesh to a specified size and centers around origin
  1059. void ComputeMeshScaling( CDXUTMesh &Mesh, D3DXMATRIX *pmScalingCenter )
  1060. {
  1061.     LPVOID pVerts = NULL;
  1062.     D3DXMatrixIdentity( pmScalingCenter );
  1063.     if( SUCCEEDED( Mesh.GetSysMemMesh()->LockVertexBuffer( 0, &pVerts ) ) )
  1064.     {
  1065.         D3DXVECTOR3 vCtr;
  1066.         float fRadius;
  1067.         if( SUCCEEDED( D3DXComputeBoundingSphere( (const D3DXVECTOR3*)pVerts,
  1068.                                                   Mesh.GetSysMemMesh()->GetNumVertices(),
  1069.                                                   Mesh.GetSysMemMesh()->GetNumBytesPerVertex(),
  1070.                                                   &vCtr, &fRadius ) ) )
  1071.         {
  1072.             D3DXMatrixTranslation( pmScalingCenter, -vCtr.x, -vCtr.y, -vCtr.z );
  1073.             D3DXMATRIXA16 m;
  1074.             D3DXMatrixScaling( &m, 1.0f / fRadius,
  1075.                                    1.0f / fRadius,
  1076.                                    1.0f / fRadius );
  1077.             D3DXMatrixMultiply( pmScalingCenter, pmScalingCenter, &m );
  1078.         }
  1079.         Mesh.GetSysMemMesh()->UnlockVertexBuffer();
  1080.     }
  1081. }
  1082.  
  1083.  
  1084. //--------------------------------------------------------------------------------------
  1085. // This callback function will be called immediately after the Direct3D device has been 
  1086. // created, which will happen during application initialization and windowed/full screen 
  1087. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  1088. // resources need to be reloaded whenever the device is destroyed. Resources created  
  1089. // here should be released in the OnDestroyDevice callback. 
  1090. //--------------------------------------------------------------------------------------
  1091. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  1092. {
  1093.     HRESULT hr;
  1094.  
  1095.     // Initialize the vertex declaration
  1096.     V_RETURN( pd3dDevice->CreateVertexDeclaration( MESHVERT::Decl, &g_pMeshDecl ) );
  1097.     V_RETURN( pd3dDevice->CreateVertexDeclaration( SHADOWVERT::Decl, &g_pShadowDecl ) );
  1098.     V_RETURN( pd3dDevice->CreateVertexDeclaration( POSTPROCVERT::Decl, &g_pPProcDecl ) );
  1099.  
  1100.     // Initialize the font
  1101.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  1102.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  1103.                          L"Arial", &g_pFont ) );
  1104.  
  1105.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  1106.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  1107.     // processing, and debugging pixel shaders requires REF.  The 
  1108.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  1109.     // shader debugger.  It enables source level debugging, prevents instruction 
  1110.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  1111.     // against the next higher available software target, which ensures that the 
  1112.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  1113.     // flags will cause slower rendering since the shaders will be unoptimized and 
  1114.     // forced into software.  See the DirectX documentation for more information about 
  1115.     // using the shader debugger.
  1116.     DWORD dwShaderFlags = 0;
  1117.     #ifdef DEBUG_VS
  1118.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  1119.     #endif
  1120.     #ifdef DEBUG_PS
  1121.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  1122.     #endif
  1123.  
  1124.     // Read the D3DX effect file
  1125.     WCHAR str[MAX_PATH];
  1126.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ShadowVolume.fx" ) );
  1127.  
  1128.     // If this fails, there should be debug output as to 
  1129.     // they the .fx file failed to compile
  1130.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  1131.                                         NULL, &g_pEffect, NULL ) );
  1132.  
  1133.     // Determine the rendering techniques to use based on device caps
  1134.     D3DCAPS9 Caps;
  1135.     V_RETURN( pd3dDevice->GetDeviceCaps( &Caps ) );
  1136.  
  1137.     if( Caps.PixelShaderVersion >= D3DPS_VERSION( 2, 0 ) )
  1138.         g_hRenderScene = g_pEffect->GetTechniqueByName( "RenderScene" );
  1139.     else
  1140.         g_hRenderScene = g_pEffect->GetTechniqueByName( "RenderScene1x" );
  1141.  
  1142.     // If 2-sided stencil is supported, use it.
  1143.     if( Caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED )
  1144.     {
  1145.         g_hRenderShadow = g_pEffect->GetTechniqueByName( "RenderShadowVolume2Sided" );
  1146.         g_hShowShadow = g_pEffect->GetTechniqueByName( "ShowShadowVolume2Sided" );
  1147.     }
  1148.     else
  1149.     {
  1150.         g_hRenderShadow = g_pEffect->GetTechniqueByName( "RenderShadowVolume" );
  1151.         g_hShowShadow = g_pEffect->GetTechniqueByName( "ShowShadowVolume" );
  1152.     }
  1153.  
  1154.     // Load the meshes
  1155.     V_RETURN( g_Background[0].Create( pd3dDevice, L"misc\\cell.x" ) );
  1156.     g_Background[0].SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1157.     V_RETURN( g_Background[1].Create( pd3dDevice, L"misc\\seafloor.x" ) );
  1158.     g_Background[1].SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1159.     V_RETURN( g_LightMesh.Create( pd3dDevice, L"misc\\sphere0.x" ) );
  1160.     g_LightMesh.SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1161.     V_RETURN( g_Mesh.Create( pd3dDevice, DEFMESHFILENAME ) );
  1162.     g_Mesh.SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1163.  
  1164.     // Compute the scaling matrix for the mesh so that the size of the mesh
  1165.     // that shows on the screen is consistent.
  1166.     ComputeMeshScaling( g_Mesh, &g_mWorldScaling );
  1167.  
  1168.     // Setup the camera's view parameters
  1169.     D3DXVECTOR3 vecEye(0.0f, 0.0f, -5.0f);
  1170.     D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  1171.     g_Camera.SetViewParams( &vecEye, &vecAt );
  1172.     g_LCamera.SetViewParams( &vecEye, &vecAt );
  1173.     g_MCamera.SetViewParams( &vecEye, &vecAt );
  1174.  
  1175.     // Create the 1x1 white default texture
  1176.     V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, 0, D3DFMT_A8R8G8B8,
  1177.                                          D3DPOOL_MANAGED, &g_pDefaultTex, NULL ) );
  1178.     D3DLOCKED_RECT lr;
  1179.     V_RETURN( g_pDefaultTex->LockRect( 0, &lr, NULL, 0 ) );
  1180.     *(LPDWORD)lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );
  1181.     V_RETURN( g_pDefaultTex->UnlockRect( 0 ) );
  1182.  
  1183.     return S_OK;
  1184. }
  1185.  
  1186.  
  1187. //--------------------------------------------------------------------------------------
  1188. // This callback function will be called immediately after the Direct3D device has been 
  1189. // reset, which will happen after a lost device scenario. This is the best location to 
  1190. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  1191. // the device is lost. Resources created here should be released in the OnLostDevice 
  1192. // callback. 
  1193. //--------------------------------------------------------------------------------------
  1194. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  1195.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  1196. {
  1197.     HRESULT hr;
  1198.  
  1199.     if( g_pFont )
  1200.         V_RETURN( g_pFont->OnResetDevice() );
  1201.     if( g_pEffect )
  1202.         V_RETURN( g_pEffect->OnResetDevice() );
  1203.  
  1204.     g_Background[0].RestoreDeviceObjects( pd3dDevice );
  1205.     g_Background[1].RestoreDeviceObjects( pd3dDevice );
  1206.     g_LightMesh.RestoreDeviceObjects( pd3dDevice );
  1207.     g_Mesh.RestoreDeviceObjects( pd3dDevice );
  1208.  
  1209.     // Create a sprite to help batch calls when drawing many lines of text
  1210.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  1211.  
  1212.     // Setup the camera's projection parameters
  1213.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  1214.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 20.0f );
  1215.     g_MCamera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  1216.     g_LCamera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  1217.     g_pEffect->SetFloat( "g_fFarClip", 20.0f - EXTRUDE_EPSILON );
  1218.     V( g_pEffect->SetMatrix( "g_mProj", g_Camera.GetProjMatrix() ) );
  1219.  
  1220.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  1221.     g_HUD.SetSize( 170, 170 );
  1222.     g_SampleUI.SetLocation( 0, pBackBufferSurfaceDesc->Height-200 );
  1223.     g_SampleUI.SetSize( pBackBufferSurfaceDesc->Width, 150 );
  1224.  
  1225.     int iY = 10;
  1226.     g_SampleUI.GetControl( IDC_BACKGROUND )->SetLocation( pBackBufferSurfaceDesc->Width - 200, iY += 24 );
  1227.     g_SampleUI.GetControl( IDC_ENABLELIGHT )->SetLocation( pBackBufferSurfaceDesc->Width - 200, iY += 24 );
  1228.     g_SampleUI.GetControl( IDC_RENDERTYPE )->SetLocation( pBackBufferSurfaceDesc->Width - 200, iY += 24 );
  1229.     g_SampleUI.GetControl( IDC_LUMINANCELABEL )->SetLocation( pBackBufferSurfaceDesc->Width - 145, iY += 30 );
  1230.     g_SampleUI.GetControl( IDC_LUMINANCE )->SetLocation( pBackBufferSurfaceDesc->Width - 145, iY += 20 );
  1231.     g_SampleUI.GetControl( IDC_CHANGEMESH )->SetLocation( pBackBufferSurfaceDesc->Width - 120, iY += 26 );
  1232.     if( g_SampleUI.GetControl( IDC_MESHFILENAME ) )
  1233.         g_SampleUI.GetControl( IDC_MESHFILENAME )->SetLocation( pBackBufferSurfaceDesc->Width - 540, iY );
  1234.  
  1235.     // Generate the shadow volume mesh
  1236.     GenerateShadowMesh( pd3dDevice, g_Mesh.GetSysMemMesh(), &g_pShadowMesh );
  1237.  
  1238.     return S_OK;
  1239. }
  1240.  
  1241.  
  1242. //--------------------------------------------------------------------------------------
  1243. // This callback function will be called once at the beginning of every frame. This is the
  1244. // best location for your application to handle updates to the scene, but is not 
  1245. // intended to contain actual rendering calls, which should instead be placed in the 
  1246. // OnFrameRender callback.  
  1247. //--------------------------------------------------------------------------------------
  1248. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  1249. {
  1250.     // Update the camera's position based on user input 
  1251.     g_Camera.FrameMove( fElapsedTime );
  1252.     g_MCamera.FrameMove( fElapsedTime );
  1253.     g_LCamera.FrameMove( fElapsedTime );
  1254. }
  1255.  
  1256.  
  1257. //--------------------------------------------------------------------------------------
  1258. // Simply renders the entire scene without any shadow handling.
  1259. void RenderScene( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, bool bRenderLight )
  1260. {
  1261.     HRESULT hr;
  1262.     D3DXMATRIXA16 mWorldView;
  1263.     D3DXMATRIXA16 mViewProj;
  1264.     D3DXMATRIXA16 mWorldViewProjection;
  1265.  
  1266.     // Get the projection & view matrix from the camera class
  1267.     D3DXMatrixMultiply( &mViewProj, g_Camera.GetViewMatrix(), g_Camera.GetProjMatrix() );
  1268.  
  1269.     // Render the lights if requested
  1270.     if( bRenderLight )
  1271.     {
  1272.         D3DXHANDLE hCurrTech;
  1273.         hCurrTech = g_pEffect->GetCurrentTechnique();  // Save the current technique
  1274.         V( g_pEffect->SetTechnique( "RenderSceneAmbient" ) );
  1275.         V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
  1276.         D3DXVECTOR4 vLightMat( 1.0f, 1.0f, 1.0f, 1.0f );
  1277.         V( g_pEffect->SetVector( "g_vMatColor", &vLightMat ) );
  1278.         UINT cPasses;
  1279.         ID3DXMesh *pMesh = g_LightMesh.GetLocalMesh();
  1280.         V( g_pEffect->Begin( &cPasses, 0 ) );
  1281.         for( UINT p = 0; p < cPasses; ++p )
  1282.         {
  1283.             V( g_pEffect->BeginPass( p ) );
  1284.             for( int i = 0; i < g_nNumLights; ++i )
  1285.             {
  1286.                 for( UINT m = 0; m < g_LightMesh.m_dwNumMaterials; ++m )
  1287.                 {
  1288.                     mWorldView = g_aLights[i].m_mWorld * *g_LCamera.GetWorldMatrix() * *g_Camera.GetViewMatrix();
  1289.                     mWorldViewProjection = mWorldView * *g_Camera.GetProjMatrix();
  1290.                     V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  1291.                     V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  1292.                     V( g_pEffect->SetVector( "g_vAmbient", &g_aLights[i].m_Color ) );
  1293.  
  1294.                     // The effect interface queues up the changes and performs them 
  1295.                     // with the CommitChanges call. You do not need to call CommitChanges if 
  1296.                     // you are not setting any parameters between the BeginPass and EndPass.
  1297.                     V( g_pEffect->CommitChanges() );
  1298.  
  1299.                     V( pMesh->DrawSubset( m ) );
  1300.                 }
  1301.             }
  1302.             V( g_pEffect->EndPass() );
  1303.         }
  1304.         V( g_pEffect->End() );
  1305.         V( g_pEffect->SetTechnique( hCurrTech ) ); // Restore the old technique
  1306.         D3DXVECTOR4 vAmb( AMBIENT, AMBIENT, AMBIENT, 1.0f );
  1307.         V( g_pEffect->SetVector( "g_vAmbient", &vAmb ) );
  1308.     }
  1309.  
  1310.     // Render the background mesh
  1311.     V( pd3dDevice->SetVertexDeclaration( g_pMeshDecl ) );
  1312.     mWorldView = g_mWorldBack[g_nCurrBackground] * *g_Camera.GetViewMatrix();
  1313.     mWorldViewProjection = g_mWorldBack[g_nCurrBackground] * mViewProj;
  1314.     V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  1315.     V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  1316.     UINT cPasses;
  1317.     V( g_pEffect->Begin( &cPasses, 0 ) );
  1318.     for( UINT p = 0; p < cPasses; ++p )
  1319.     {
  1320.         V( g_pEffect->BeginPass( p ) );
  1321.         ID3DXMesh *pMesh = g_Background[g_nCurrBackground].GetLocalMesh();
  1322.         for( UINT i = 0; i < g_Background[g_nCurrBackground].m_dwNumMaterials; ++i )
  1323.         {
  1324.             V( g_pEffect->SetVector( "g_vMatColor", (D3DXVECTOR4*)&g_Background[g_nCurrBackground].m_pMaterials[i].Diffuse ) );
  1325.             if( g_Background[g_nCurrBackground].m_pTextures[i] )
  1326.                 V( g_pEffect->SetTexture( "g_txScene", g_Background[g_nCurrBackground].m_pTextures[i] ) )
  1327.             else
  1328.                 V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
  1329.             // The effect interface queues up the changes and performs them 
  1330.             // with the CommitChanges call. You do not need to call CommitChanges if 
  1331.             // you are not setting any parameters between the BeginPass and EndPass.
  1332.             V( g_pEffect->CommitChanges() );
  1333.             V( pMesh->DrawSubset( i ) );
  1334.         }
  1335.         V( g_pEffect->EndPass() );
  1336.     }
  1337.     V( g_pEffect->End() );
  1338.  
  1339.     // Render the mesh
  1340.     V( pd3dDevice->SetVertexDeclaration( g_pMeshDecl ) );
  1341.     mWorldView = g_mWorldScaling * *g_MCamera.GetWorldMatrix() * *g_Camera.GetViewMatrix();
  1342.     mWorldViewProjection = mWorldView * *g_Camera.GetProjMatrix();
  1343.     V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  1344.     V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  1345.     V( g_pEffect->Begin( &cPasses, 0 ) );
  1346.     for( UINT p = 0; p < cPasses; ++p )
  1347.     {
  1348.         V( g_pEffect->BeginPass( p ) );
  1349.         ID3DXMesh *pMesh = g_Mesh.GetLocalMesh();
  1350.         for( UINT i = 0; i < g_Mesh.m_dwNumMaterials; ++i )
  1351.         {
  1352.             V( g_pEffect->SetVector( "g_vMatColor", (D3DXVECTOR4*)&g_Mesh.m_pMaterials[i].Diffuse ) );
  1353.             if( g_Mesh.m_pTextures[i] )
  1354.                 V( g_pEffect->SetTexture( "g_txScene", g_Mesh.m_pTextures[i] ) )
  1355.             else
  1356.                 V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
  1357.             // The effect interface queues up the changes and performs them 
  1358.             // with the CommitChanges call. You do not need to call CommitChanges if 
  1359.             // you are not setting any parameters between the BeginPass and EndPass.
  1360.             V( g_pEffect->CommitChanges() );
  1361.             V( pMesh->DrawSubset( i ) );
  1362.         }
  1363.         V( g_pEffect->EndPass() );
  1364.     }
  1365.     V( g_pEffect->End() );
  1366. }
  1367.  
  1368.  
  1369. //--------------------------------------------------------------------------------------
  1370. // This callback function will be called at the end of every frame to perform all the 
  1371. // rendering calls for the scene, and it will also be called if the window needs to be 
  1372. // repainted. After this function has returned, the sample framework will call 
  1373. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  1374. //--------------------------------------------------------------------------------------
  1375. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  1376. {
  1377.     HRESULT hr;
  1378.  
  1379.     // Clear the render target and the zbuffer
  1380.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 66, 75, 121), 1.0f, 0 ) );
  1381.  
  1382.     // Render the scene
  1383.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  1384.     {
  1385.         DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"Demonstration Code" );
  1386.  
  1387.         // First, render the scene with only ambient lighting
  1388.         {
  1389.             CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Scene Ambient" );
  1390.  
  1391.             g_pEffect->SetTechnique( "RenderSceneAmbient" );
  1392.             D3DXVECTOR4 vAmb( AMBIENT, AMBIENT, AMBIENT, 1.0f );
  1393.             V( g_pEffect->SetVector( "g_vAmbient", &vAmb ) );
  1394.             RenderScene( pd3dDevice, fTime, fElapsedTime, true );
  1395.         }
  1396.  
  1397.         // Now process the lights.  For each light in the scene,
  1398.         // render the shadow volume, then render the scene with
  1399.         // stencil enabled.
  1400.  
  1401.         {
  1402.             CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Shadow" );
  1403.             
  1404.             for( int L = 0; L < g_nNumLights; ++L )
  1405.             {
  1406.                 // Clear the stencil buffer
  1407.                 if( g_RenderType != RENDERTYPE_COMPLEXITY )
  1408.                     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, D3DCOLOR_ARGB(0, 170, 170, 170), 1.0f, 0 ) );
  1409.                 
  1410.                 D3DXVECTOR4 vLight( g_aLights[L].m_Position.x, g_aLights[L].m_Position.y, g_aLights[L].m_Position.z, 1.0f );
  1411.                 D3DXVec4Transform( &vLight, &vLight, g_LCamera.GetWorldMatrix() );
  1412.                 D3DXVec4Transform( &vLight, &vLight, g_Camera.GetViewMatrix() );
  1413.                 V( g_pEffect->SetVector( "g_vLightView", &vLight ) );
  1414.                 V( g_pEffect->SetVector( "g_vLightColor", &g_aLights[L].m_Color ) );
  1415.                 
  1416.                 // Render the shadow volume
  1417.                 switch( g_RenderType )
  1418.                 {
  1419.                 case RENDERTYPE_COMPLEXITY:
  1420.                     g_pEffect->SetTechnique( "RenderShadowVolumeComplexity" );
  1421.                     break;
  1422.                 case RENDERTYPE_SHADOWVOLUME:
  1423.                     g_pEffect->SetTechnique( g_hShowShadow );
  1424.                     break;
  1425.                 default:
  1426.                     g_pEffect->SetTechnique( g_hRenderShadow );
  1427.                 }
  1428.                 
  1429.                 g_pEffect->SetVector( "g_vShadowColor", &g_vShadowColor[L] );
  1430.                 
  1431.                 // If there was an error generating the shadow volume,
  1432.                 // skip rendering the shadow mesh.  The scene will show
  1433.                 // up without shadow.
  1434.                 if( g_pShadowMesh )
  1435.                 {
  1436.                     V( pd3dDevice->SetVertexDeclaration( g_pShadowDecl ) );
  1437.                     UINT cPasses;
  1438.                     V( g_pEffect->Begin( &cPasses, 0 ) );
  1439.                     for( UINT i = 0; i < cPasses; ++i )
  1440.                     {
  1441.                         V( g_pEffect->BeginPass( i ) );
  1442.                         V( g_pEffect->CommitChanges() );
  1443.                         V( g_pShadowMesh->DrawSubset( 0 ) );
  1444.                         V( g_pEffect->EndPass() );
  1445.                     }
  1446.                     V( g_pEffect->End() );
  1447.                 }
  1448.                 
  1449.                 //
  1450.                 // Render the scene with stencil and lighting enabled.
  1451.                 //
  1452.                 if( g_RenderType != RENDERTYPE_COMPLEXITY )
  1453.                 {
  1454.                     g_pEffect->SetTechnique( g_hRenderScene );
  1455.                     RenderScene( pd3dDevice, fTime, fElapsedTime, false );
  1456.                 }
  1457.             }
  1458.         }
  1459.  
  1460.         if( g_RenderType == RENDERTYPE_COMPLEXITY )
  1461.         {
  1462.             CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Complexity" );
  1463.  
  1464.             // Clear the render target
  1465.             V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0 ) );
  1466.  
  1467.             // Render scene complexity visualization
  1468.             const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  1469.             POSTPROCVERT quad[4] =
  1470.             {
  1471.                 { -0.5f,                                                -0.5f, 0.5f, 1.0f },
  1472.                 { pd3dsdBackBuffer->Width-0.5f,                         -0.5f, 0.5f, 1.0f },
  1473.                 { -0.5f,                        pd3dsdBackBuffer->Height-0.5f, 0.5f, 1.0f },
  1474.                 { pd3dsdBackBuffer->Width-0.5f, pd3dsdBackBuffer->Height-0.5f, 0.5f, 1.0f }
  1475.             };
  1476.  
  1477.             pd3dDevice->SetVertexDeclaration( g_pPProcDecl );
  1478.             g_pEffect->SetTechnique( "RenderComplexity" );
  1479.             UINT cPasses;
  1480.             g_pEffect->Begin( &cPasses, 0 );
  1481.             for( UINT p = 0; p < cPasses; ++p )
  1482.             {
  1483.                 g_pEffect->BeginPass( p );
  1484.                 pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, quad, sizeof(POSTPROCVERT) );
  1485.                 g_pEffect->EndPass();
  1486.             }
  1487.             g_pEffect->End();
  1488.         }
  1489.  
  1490.         DXUT_EndPerfEvent(); // end of draw code
  1491.  
  1492.         // Miscellaneous rendering
  1493.         {
  1494.             CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"HUD / Stats" );
  1495.             
  1496.             RenderText();
  1497.             g_HUD.OnRender( fElapsedTime );
  1498.             g_SampleUI.OnRender( fElapsedTime );
  1499.         }
  1500.  
  1501.         V( pd3dDevice->EndScene() );
  1502.     }
  1503. }
  1504.  
  1505.  
  1506. //--------------------------------------------------------------------------------------
  1507. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  1508. // efficient text rendering.
  1509. //--------------------------------------------------------------------------------------
  1510. void RenderText()
  1511. {
  1512.     // The helper object simply helps keep track of text position, and color
  1513.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  1514.     // If NULL is passed in as the sprite object, then it will work however the 
  1515.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  1516.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  1517.     const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  1518.  
  1519.     // Output statistics
  1520.     txtHelper.Begin();
  1521.     txtHelper.SetInsertionPos( 5, 5 );
  1522.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  1523.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  1524.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  1525.  
  1526.     // Draw help
  1527.     if( g_bShowHelp )
  1528.     {
  1529.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-80 );
  1530.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  1531.         txtHelper.DrawTextLine( L"Controls (F1 to hide):" );
  1532.  
  1533.         txtHelper.SetInsertionPos( 20, pd3dsdBackBuffer->Height-65 );
  1534.         txtHelper.DrawTextLine( L"Camera control: Left mouse\n"
  1535.                                 L"Mesh control: Right mouse\n"
  1536.                                 L"Light control: Middle mouse\n"
  1537.                                 L"Quit: ESC" );
  1538.     }
  1539.     else
  1540.     {
  1541.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-25 );
  1542.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1543.         txtHelper.DrawTextLine( L"Press F1 for help" );
  1544.     }
  1545.  
  1546.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1547.     if( !(g_bLeftButtonDown || g_bMiddleButtonDown || g_bRightButtonDown) )
  1548.     {
  1549.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width / 2 - 90, pd3dsdBackBuffer->Height - 40 );
  1550.         txtHelper.DrawTextLine( L"\nW/S/A/D/Q/E to move camera." );
  1551.     } else
  1552.     {
  1553.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width / 2 - 70, pd3dsdBackBuffer->Height - 40 );
  1554.         if( g_bLeftButtonDown )
  1555.         {
  1556.             txtHelper.DrawTextLine( L"Camera Control Mode" );
  1557.         } else
  1558.         if( g_bMiddleButtonDown )
  1559.         {
  1560.             txtHelper.DrawTextLine( L"Light Control Mode" );
  1561.         }
  1562.         if( g_bRightButtonDown )
  1563.         {
  1564.             txtHelper.DrawTextLine( L"Model Control Mode" );
  1565.         }
  1566.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width / 2 - 130, pd3dsdBackBuffer->Height - 25 );
  1567.         txtHelper.DrawTextLine( L"Move mouse to rotate. W/S/A/D/Q/E to move." );
  1568.     }
  1569.  
  1570.     if( g_RenderType == RENDERTYPE_COMPLEXITY )
  1571.     {
  1572.         txtHelper.SetInsertionPos( 5, 70 );
  1573.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1574.         txtHelper.DrawTextLine( L"Shadow volume complexity:" );
  1575.         txtHelper.SetInsertionPos( 5, 90 );
  1576.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 1.0f, 1.0f ) );
  1577.         txtHelper.DrawTextLine( L"1 to 5 fills\n" );
  1578.         txtHelper.SetForegroundColor( D3DXCOLOR( 0.0f, 0.0f, 1.0f, 1.0f ) );
  1579.         txtHelper.DrawTextLine( L"6 to 10 fills\n" );
  1580.         txtHelper.SetForegroundColor( D3DXCOLOR( 0.0f, 1.0f, 1.0f, 1.0f ) );
  1581.         txtHelper.DrawTextLine( L"11 to 20 fills\n" );
  1582.         txtHelper.SetForegroundColor( D3DXCOLOR( 0.0f, 1.0f, 0.0f, 1.0f ) );
  1583.         txtHelper.DrawTextLine( L"21 to 30 fills\n" );
  1584.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  1585.         txtHelper.DrawTextLine( L"31 to 40 fills\n" );
  1586.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.5f, 0.0f, 1.0f ) );
  1587.         txtHelper.DrawTextLine( L"41 to 50 fills\n" );
  1588.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );
  1589.         txtHelper.DrawTextLine( L"51 to 70 fills\n" );
  1590.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1591.         txtHelper.DrawTextLine( L"71 or more fills\n" );
  1592.     }
  1593.  
  1594.     // Display an error message if unable to generate shadow mesh
  1595.     if( !g_pShadowMesh )
  1596.     {
  1597.         txtHelper.SetInsertionPos( 5, 35 );
  1598.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );
  1599.         txtHelper.DrawTextLine( L"Unable to generate closed shadow volume for this mesh\n" );
  1600.         txtHelper.DrawTextLine( L"No shadow will be rendered" );
  1601.     }
  1602.  
  1603.     txtHelper.End();
  1604. }
  1605.  
  1606.  
  1607. //--------------------------------------------------------------------------------------
  1608. // Before handling window messages, the sample framework passes incoming windows 
  1609. // messages to the application through this callback function. If the application sets 
  1610. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  1611. //--------------------------------------------------------------------------------------
  1612. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  1613. {
  1614.     // Give the dialogs a chance to handle the message first
  1615.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  1616.     if( *pbNoFurtherProcessing )
  1617.         return 0;
  1618.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  1619.     if( *pbNoFurtherProcessing )
  1620.         return 0;
  1621.  
  1622.     // Pass all remaining windows messages to camera so it can respond to user input
  1623.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1624.     g_MCamera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1625.     g_LCamera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1626.  
  1627.     return 0;
  1628. }
  1629.  
  1630.  
  1631. //--------------------------------------------------------------------------------------
  1632. // As a convenience, the sample framework inspects the incoming windows messages for
  1633. // keystroke messages and decodes the message parameters to pass relevant keyboard
  1634. // messages to the application.  The framework does not remove the underlying keystroke 
  1635. // messages, which are still passed to the application's MsgProc callback.
  1636. //--------------------------------------------------------------------------------------
  1637. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  1638. {
  1639.     if( bKeyDown )
  1640.     {
  1641.         switch( nChar )
  1642.         {
  1643.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  1644.         }
  1645.     }
  1646. }
  1647.  
  1648.  
  1649. void CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos )
  1650. {
  1651.     bool bOldLeftButtonDown = g_bLeftButtonDown;
  1652.     bool bOldRightButtonDown = g_bRightButtonDown;
  1653.     bool bOldMiddleButtonDown = g_bMiddleButtonDown;
  1654.     g_bLeftButtonDown = bLeftButtonDown;
  1655.     g_bMiddleButtonDown = bMiddleButtonDown;
  1656.     g_bRightButtonDown = bRightButtonDown;
  1657.  
  1658.     if( bOldLeftButtonDown && !g_bLeftButtonDown )
  1659.     {
  1660.         // Disable movement
  1661.         g_Camera.SetEnablePositionMovement( false );
  1662.     } else
  1663.     if( !bOldLeftButtonDown && g_bLeftButtonDown )
  1664.     {
  1665.         // Enable movement
  1666.         g_Camera.SetEnablePositionMovement( true );
  1667.     }
  1668.  
  1669.     if( bOldRightButtonDown && !g_bRightButtonDown )
  1670.     {
  1671.         // Disable movement
  1672.         g_MCamera.SetEnablePositionMovement( false );
  1673.     } else
  1674.     if( !bOldRightButtonDown && g_bRightButtonDown )
  1675.     {
  1676.         // Enable movement
  1677.         g_MCamera.SetEnablePositionMovement( true );
  1678.         g_Camera.SetEnablePositionMovement( false );
  1679.     }
  1680.  
  1681.     if( bOldMiddleButtonDown && !g_bMiddleButtonDown )
  1682.     {
  1683.         // Disable movement
  1684.         g_LCamera.SetEnablePositionMovement( false );
  1685.     } else
  1686.     if( !bOldMiddleButtonDown && g_bMiddleButtonDown )
  1687.     {
  1688.         // Enable movement
  1689.         g_LCamera.SetEnablePositionMovement( true );
  1690.         g_Camera.SetEnablePositionMovement( false );
  1691.     }
  1692.  
  1693.     // If no mouse button is down at all, enable camera movement.
  1694.     if( !g_bLeftButtonDown && !g_bRightButtonDown && !g_bMiddleButtonDown )
  1695.         g_Camera.SetEnablePositionMovement( true );
  1696. }
  1697.  
  1698.  
  1699. //--------------------------------------------------------------------------------------
  1700. // Handles the GUI events
  1701. //--------------------------------------------------------------------------------------
  1702. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  1703. {
  1704.     switch( nControlID )
  1705.     {
  1706.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  1707.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  1708.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  1709.         case IDC_RENDERTYPE:
  1710.             g_RenderType = (RENDER_TYPE)(size_t)((CDXUTComboBox*)pControl)->GetSelectedData();
  1711.             break;
  1712.         case IDC_ENABLELIGHT:
  1713.             if( nEvent == EVENT_COMBOBOX_SELECTION_CHANGED )
  1714.             {
  1715.                 g_nNumLights = (int)(size_t)g_SampleUI.GetComboBox( IDC_ENABLELIGHT )->GetSelectedData();
  1716.             }
  1717.             break;
  1718.         case IDC_LUMINANCE:
  1719.             if( nEvent == EVENT_SLIDER_VALUE_CHANGED )
  1720.             {
  1721.                 float fLuminance = float( ((CDXUTSlider *)pControl)->GetValue() );
  1722.                 WCHAR wszText[50];
  1723.                 swprintf( wszText, L"Luminance: %.1f", fLuminance );
  1724.                 g_SampleUI.GetStatic( IDC_LUMINANCELABEL )->SetText( wszText );
  1725.  
  1726.                 for( int i = 0; i < MAX_NUM_LIGHTS; ++i )
  1727.                 {
  1728.                     if( g_aLights[i].m_Color.x > 0.5f )
  1729.                         g_aLights[i].m_Color.x = fLuminance;
  1730.                     if( g_aLights[i].m_Color.y > 0.5f )
  1731.                         g_aLights[i].m_Color.y = fLuminance;
  1732.                     if( g_aLights[i].m_Color.z > 0.5f )
  1733.                         g_aLights[i].m_Color.z = fLuminance;
  1734.                 }
  1735.             }
  1736.         case IDC_BACKGROUND:
  1737.             if( nEvent == EVENT_COMBOBOX_SELECTION_CHANGED )
  1738.             {
  1739.                 g_nCurrBackground = (int)(size_t)g_SampleUI.GetComboBox( IDC_BACKGROUND )->GetSelectedData();
  1740.             }
  1741.             break;
  1742.         case IDC_MESHFILENAME:
  1743.         {
  1744.             if( nEvent == EVENT_EDITBOX_CHANGE )
  1745.                 break;
  1746.  
  1747.             CDXUTMesh NewMesh;
  1748.  
  1749.             if( SUCCEEDED( NewMesh.Create( DXUTGetD3DDevice(), g_SampleUI.GetIMEEditBox( IDC_MESHFILENAME )->GetText() ) ) &&
  1750.                 SUCCEEDED( NewMesh.SetVertexDecl( DXUTGetD3DDevice(), MESHVERT::Decl ) ) &&
  1751.                 SUCCEEDED( NewMesh.RestoreDeviceObjects( DXUTGetD3DDevice() ) ) )
  1752.             {
  1753.                 g_Mesh.InvalidateDeviceObjects();
  1754.                 g_Mesh.Destroy();
  1755.                 g_Mesh = NewMesh;
  1756.                 ZeroMemory( &NewMesh, sizeof(NewMesh) );
  1757.                 ComputeMeshScaling( g_Mesh, &g_mWorldScaling );
  1758.  
  1759.                 // Generate the shadow mesh
  1760.                 SAFE_RELEASE( g_pShadowMesh );
  1761.                 GenerateShadowMesh( DXUTGetD3DDevice(), g_Mesh.GetSysMemMesh(), &g_pShadowMesh );
  1762.             }
  1763.  
  1764.             // Fall through to clean up the edit box and button
  1765.         }
  1766.         case IDC_CHANGEMESH:
  1767.         {
  1768.             const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  1769.             if( g_SampleUI.GetControl( IDC_MESHFILENAME ) )
  1770.             {
  1771.                 // If the edit box exists, clean up.
  1772.                 g_SampleUI.RemoveControl( IDC_MESHFILENAME );
  1773.                 // Change the button text back to "Change mesh"
  1774.                 g_SampleUI.GetButton( IDC_CHANGEMESH )->SetText( L"Change mesh" );
  1775.             } else
  1776.             {
  1777.                 // Create a new edit box.
  1778.                 g_SampleUI.AddIMEEditBox( IDC_MESHFILENAME, L"", pd3dsdBackBuffer->Width - 540, 158, 415, 34 );
  1779.                 g_SampleUI.GetIMEEditBox( IDC_MESHFILENAME )->SetText( L"Type mesh name and press Enter", true );
  1780.                 g_SampleUI.RequestFocus( g_SampleUI.GetControl( IDC_MESHFILENAME ) );
  1781.                 // Change the button text to "Cancel"
  1782.                 g_SampleUI.GetButton( IDC_CHANGEMESH )->SetText( L"Cancel" );
  1783.             }
  1784.             break;
  1785.         }
  1786.     }
  1787. }
  1788.  
  1789.  
  1790. //--------------------------------------------------------------------------------------
  1791. // This callback function will be called immediately after the Direct3D device has 
  1792. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  1793. // in the OnResetDevice callback should be released here, which generally includes all 
  1794. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  1795. // information about lost devices.
  1796. //--------------------------------------------------------------------------------------
  1797. void CALLBACK OnLostDevice()
  1798. {
  1799.     g_Background[0].InvalidateDeviceObjects();
  1800.     g_Background[1].InvalidateDeviceObjects();
  1801.     g_LightMesh.InvalidateDeviceObjects();
  1802.     g_Mesh.InvalidateDeviceObjects();
  1803.     SAFE_RELEASE( g_pShadowMesh );
  1804.  
  1805.     if( g_pFont )
  1806.         g_pFont->OnLostDevice();
  1807.     if( g_pEffect )
  1808.         g_pEffect->OnLostDevice();
  1809.     SAFE_RELEASE(g_pTextSprite);
  1810. }
  1811.  
  1812.  
  1813. //--------------------------------------------------------------------------------------
  1814. // This callback function will be called immediately after the Direct3D device has 
  1815. // been destroyed, which generally happens as a result of application termination or 
  1816. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  1817. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  1818. //--------------------------------------------------------------------------------------
  1819. void CALLBACK OnDestroyDevice()
  1820. {
  1821.     g_Background[0].Destroy();
  1822.     g_Background[1].Destroy();
  1823.     g_LightMesh.Destroy();
  1824.     g_Mesh.Destroy();
  1825.  
  1826.     SAFE_RELEASE( g_pDefaultTex );
  1827.     SAFE_RELEASE( g_pEffect );
  1828.     SAFE_RELEASE( g_pFont );
  1829.     SAFE_RELEASE( g_pMeshDecl );
  1830.     SAFE_RELEASE( g_pShadowDecl );
  1831.     SAFE_RELEASE( g_pPProcDecl );
  1832. }
  1833.